import UIKit
import CoreGraphics
import QuartzCore
@available(iOSApplicationExtension, unavailable)
@objc public final class IQKeyboardManager: NSObject {
    @objc public static let shared = IQKeyboardManager()
    internal static let kIQCGPointInvalid = CGPoint.init(x: CGFloat.greatestFiniteMagnitude, y: CGFloat.greatestFiniteMagnitude)
    @objc public var enable = false {
        didSet {
            if enable, !oldValue {
                if let notification = keyboardShowNotification {
                    keyboardWillShow(notification)
                }
                showLog("Enabled")
            } else if !enable, oldValue {  
                keyboardWillHide(nil)
                showLog("Disabled")
            }
        }
    }
    @objc public var keyboardDistanceFromTextField: CGFloat = 10.0
    @objc public var enableAutoToolbar = true {
        didSet {
            if privateIsEnableAutoToolbar() {
                addToolbarIfRequired()
            } else {
                removeToolbarIfRequired()
            }
            let enableToolbar = enableAutoToolbar ? "Yes" : "NO"
            showLog("enableAutoToolbar: \(enableToolbar)")
        }
    }
    @objc public var toolbarManageBehaviour = IQAutoToolbarManageBehaviour.bySubviews
    @objc public var shouldToolbarUsesTextFieldTintColor = false
    @objc public var toolbarTintColor: UIColor?
    @objc public var toolbarBarTintColor: UIColor?
    @objc public var previousNextDisplayMode = IQPreviousNextDisplayMode.default
    @objc public var toolbarPreviousBarButtonItemImage: UIImage?
    @objc public var toolbarNextBarButtonItemImage: UIImage?
    @objc public var toolbarDoneBarButtonItemImage: UIImage?
    @objc public var toolbarPreviousBarButtonItemText: String?
    @objc public var toolbarPreviousBarButtonItemAccessibilityLabel: String?
    @objc public var toolbarNextBarButtonItemText: String?
    @objc public var toolbarNextBarButtonItemAccessibilityLabel: String?
    @objc public var toolbarDoneBarButtonItemText: String?
    @objc public var toolbarDoneBarButtonItemAccessibilityLabel: String?
    @objc public var toolbarTitlBarButtonItemAccessibilityLabel: String?
    @objc public var shouldShowToolbarPlaceholder = true
    @objc public var placeholderFont: UIFont?
    @objc public var placeholderColor: UIColor?
    @objc public var placeholderButtonColor: UIColor?
    @objc public var overrideKeyboardAppearance = false
    @objc public var keyboardAppearance = UIKeyboardAppearance.default
    @objc public var shouldResignOnTouchOutside = false {
        didSet {
            resignFirstResponderGesture.isEnabled = privateShouldResignOnTouchOutside()
            let shouldResign = shouldResignOnTouchOutside ? "Yes" : "NO"
            showLog("shouldResignOnTouchOutside: \(shouldResign)")
        }
    }
    @objc lazy public var resignFirstResponderGesture: UITapGestureRecognizer = {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.tapRecognized(_:)))
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        return tapGesture
    }()
    @objc @discardableResult public func resignFirstResponder() -> Bool {
        guard let textFieldRetain = textFieldView else {
            return false
        }
        guard textFieldRetain.resignFirstResponder() else {
            showLog("Refuses to resign first responder: \(textFieldRetain)")
            textFieldRetain.becomeFirstResponder()
            return false
        }
        return true
    }
    @objc public var shouldPlayInputClicks = true
    @objc public var layoutIfNeededOnUpdate = false
    @objc public var disabledDistanceHandlingClasses  = [UIViewController.Type]()
    @objc public var enabledDistanceHandlingClasses  = [UIViewController.Type]()
    @objc public var disabledToolbarClasses  = [UIViewController.Type]()
    @objc public var enabledToolbarClasses  = [UIViewController.Type]()
    @objc public var toolbarPreviousNextAllowedClasses  = [UIView.Type]()
    @objc public var disabledTouchResignedClasses  = [UIViewController.Type]()
    @objc public var enabledTouchResignedClasses  = [UIViewController.Type]()
    @objc public var touchResignedGestureIgnoreClasses  = [UIView.Type]()
    @objc public func registerTextFieldViewClass(_ aClass: UIView.Type, didBeginEditingNotificationName: String, didEndEditingNotificationName: String) {
        NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldViewDidBeginEditing(_:)), name: Notification.Name(rawValue: didBeginEditingNotificationName), object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldViewDidEndEditing(_:)), name: Notification.Name(rawValue: didEndEditingNotificationName), object: nil)
    }
    @objc public func unregisterTextFieldViewClass(_ aClass: UIView.Type, didBeginEditingNotificationName: String, didEndEditingNotificationName: String) {
        NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: didBeginEditingNotificationName), object: nil)
        NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: didEndEditingNotificationName), object: nil)
    }
    internal struct WeakObjectContainer {
        weak var object: AnyObject?
    }
    override init() {
        super.init()
        self.registerAllNotifications()
        resignFirstResponderGesture.isEnabled = shouldResignOnTouchOutside
        disabledDistanceHandlingClasses.append(UITableViewController.self)
        disabledDistanceHandlingClasses.append(UIAlertController.self)
        disabledToolbarClasses.append(UIAlertController.self)
        disabledTouchResignedClasses.append(UIAlertController.self)
        toolbarPreviousNextAllowedClasses.append(UITableView.self)
        toolbarPreviousNextAllowedClasses.append(UICollectionView.self)
        toolbarPreviousNextAllowedClasses.append(IQPreviousNextView.self)
        touchResignedGestureIgnoreClasses.append(UIControl.self)
        touchResignedGestureIgnoreClasses.append(UINavigationBar.self)
        DispatchQueue.main.async {
            let textField = UITextField()
            textField.addDoneOnKeyboardWithTarget(nil, action: #selector(self.doneAction(_:)))
            textField.addPreviousNextDoneOnKeyboardWithTarget(nil, previousAction: #selector(self.previousAction(_:)), nextAction: #selector(self.nextAction(_:)), doneAction: #selector(self.doneAction(_:)))
        }
    }
    deinit {
        enable = false
    }
    internal func keyWindow() -> UIWindow? {
        if let keyWindow = textFieldView?.window {
            return keyWindow
        } else {
            struct Static {
                static weak var keyWindow: UIWindow?
            }
            var originalKeyWindow: UIWindow?
            #if swift(>=5.1)
            if #available(iOS 13, *) {
                originalKeyWindow = UIApplication.shared.connectedScenes
                    .compactMap { $0 as? UIWindowScene }
                    .flatMap { $0.windows }
                    .first(where: { $0.isKeyWindow })
            } else {
                originalKeyWindow = UIApplication.shared.keyWindow
            }
            #else
            originalKeyWindow = UIApplication.shared.keyWindow
            #endif
            if let originalKeyWindow = originalKeyWindow {
                Static.keyWindow = originalKeyWindow
            }
            return Static.keyWindow
        }
    }
    @objc public func reloadLayoutIfNeeded() {
        guard privateIsEnabled(),
            keyboardShowing,
            topViewBeginOrigin.equalTo(IQKeyboardManager.kIQCGPointInvalid) == false, let textFieldView = textFieldView,
            textFieldView.isAlertViewTextField() == false else {
                return
        }
        self.adjustPosition()
    }
}
@available(iOSApplicationExtension, unavailable)
extension IQKeyboardManager: UIGestureRecognizerDelegate {
    @objc internal func tapRecognized(_ gesture: UITapGestureRecognizer) {
        if gesture.state == .ended {
            resignFirstResponder()
        }
    }
    @objc public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
    @objc public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        for ignoreClass in touchResignedGestureIgnoreClasses where touch.view?.isKind(of: ignoreClass) ?? false {
            return false
        }
        return true
    }
}
